iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0

今天來聊聊怎麼在 FastAPI 使用環境變數~

為什麼需要使用環境變數?

在很多時候,我們會希望某些參數不要寫死,要依據各種情況進行調整;又或者是,某些參數本身是機密,不適合放到公開的平台上 (例如:Github),此時,我們就可以考慮讓這些參數是以環境變數的方式讓我們的主程式讀取。

以 FastAPI 來說,常見的環境變數包括

  1. host、port
  2. openapi 的 URL
  3. DB 連線的 URL
  4. JWT token 的 secret key

第一個是為了方便我們後續在測試環境和部屬環境之間做切換,其餘三個則是因為它本身比較機密。

Day 07 有介紹到 openapi_url 設定,可以用來決定是否啟用自動生成 API 文件

怎麼使用環境變數?

這些環境變數,通常我們會把它存在 .env 的檔案內,再透過合適的套件來讀取它們,以 FastAPI 來說,使用 pydantic 是最適合的。

在使用之前,需要安裝 pydantic-settings (安裝指令為 pip install pydantic-settings),但如果當初安裝 FastAPI 是使用 pip install "fastapi[all]",則不用再另外安裝了。

來看看官方的範例

# config.py
from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

    model_config = SettingsConfigDict(env_file=".env")

settings = Settings()
print(settings.app_name, settings.admin_email, settings.items_per_user)

config.py 的同一層新增一個 .env

ADMIN_EMAIL="admin@example.com"
APP_NAME="CoolApp"

執行後就會在 terminal 印出

CoolApp admin@example.com 50

應用在 FastAPI

接著我們回到 FastAPI 主程式 main.py,將 config.py 讀取的變數 import 進來

# main.py
from fastapi import FastAPI
from config import Settings

app = FastAPI()

settings = Settings()

@app.get("/info")
async def info():
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }

接著用 postman 測試一下

代表我們有成功的讀取到 .env 中的設定了~

需要注意的是,此時如果我們修改了 .env 中的內容,是不會對 API 有任何影響的,因為它是在啟動的時候讀取的,之後就不會再讀取了。如果想要讓改動生效,就要重新啟動 FastAPI。

這邊我的寫法與官網範例略有差異

TOML,環境變數格式新選擇?

.env 這種格式是一代經典,但當變數變多時,它的可閱讀性就很差。另外,在使用上也有一些限制,例如:基本上只支援字串和數字、參數們都是同一層級 (沒辦法分類)。因此,TOML 就誕生了,它可以支援各種型別,也可以分類。Python 有很多套件都可以解析 .toml 格式的內容,只可惜 pydantic 不支援,並且似乎短時間內沒有打算開發這個功能 (參考這篇 issue)。

我個人在工作上是使用 .toml 的,大家有興趣的話也歡迎去嘗試看看 XD

案例分享

最後來聊聊 pydantic 版本升級

FastAPI 在今年 7 月的 0.100.0 版開始支援 Pydantic v2,而現在安裝 FastAPI 時,預設就是安裝 pydantic v2 (我們在 Day 02 中安裝的就是 2.3.0 版)

對於那些 7 月以前開始開發的專案,如果沒有記錄版本在 requirements.txt 內,就會產生影響,而不幸的,我們公司就是這樣QQ

如果是已經有裝好環境的,沒有影響,但如果有其他同事後來才需要幫忙開發或測試,他們在安裝環境時就會自動裝 v2,但語法仍是 v1,因此就會產生錯誤。

這件事要解決也不難,最簡單的辦法就是把 pydantic 版本降回去 v1,因為 FastAPI 在支援 pydantic v2 的同時,仍然支援 v1。

但這終究不是長久之計,FastAPI 總有一天會停止支援 pydantic v1 的,而且 v2 比起 v1 有許多優點 (例如:效能優化),是值得升級的。經過評估,我發現要調整的語法不多,主要就是環境變數這塊而已,因此最終我花了一些時間把語法都改成 v2 版了。

這是舊版 (v1) 的寫法

from pydantic import BaseSettings

class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

    class Config:
        env_file = ".env"

而這是新版 (v2) 的寫法

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

    model_config = SettingsConfigDict(env_file=".env")

FastAPI 官網有一個優點,那就是同時準備了不同版的程式碼給大家參考,對照起來也很方便,只可惜我次我是看完 pydantic 文件才發現原來 FastAPI 官網有可以參考的範例

另一位同事也有遇到一樣的問題,但他除了環境變數之外,還有一個地方有問題,那就是 FastAPI Utilities。FastAPI Utilities 內有一些好用的功能,但他最近有段時間沒維護了 (上次更新是今年 3 月),只支援到 pydantic v1。儘管 Issue 中也有人提到希望支援 pydantic v2,但看起來被發無聲卡了QQ。好在後來有看到有一個替代方案 ── FastApi-RESTful,它是從 FastAPI Utilities fork 出來的,並且有支援到 pydantic v2,因此問題得以順利解決。

重點回顧

今天我們介紹了怎麼使用環境變數,以及在 FastAPI 上的應用,希望對大家有幫助~


上一篇
[Day 09] 做出一個網站:Jinja Template
下一篇
[Day 11] Middleware 與 CORS
系列文
FastAPI 開發筆記:從新手到專家的成長之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言